package com.mxpio.erp.workshop.controller;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.collection.CollectionUtil;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.quality.entity.MoInQualityOrder;
import com.mxpio.erp.common.quality.entity.MoInQualityOrderLine;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpio.erp.common.workshop.entity.*;
import com.mxpio.erp.common.workshop.service.ManufactureOrderRouteService;
import com.mxpio.erp.common.workshop.vo.MaterialFeedingDetailVO;
import com.mxpio.erp.common.workshop.vo.MoCostAccountingVO;
import com.mxpio.erp.common.workshop.vo.MoStortageAnalysisVO;
import com.mxpio.erp.workshop.policy.impl.DefaultDefectivePolicy;
import com.mxpioframework.jpa.policy.CrudContext;
import com.mxpioframework.jpa.policy.impl.SmartCrudPolicyAdapter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.jpa.model.Order;
import com.mxpio.erp.common.order.policy.OrderContext;
import com.mxpio.erp.common.order.service.OrderService;
import com.mxpio.erp.common.vo.OrderExcuteVo;
import com.mxpio.erp.common.workshop.service.ManufactureOrderItemService;
import com.mxpio.erp.common.workshop.service.ManufactureOrderService;
import com.mxpio.erp.workshop.policy.impl.DefaultExecuteMoPolicy;
import com.mxpio.erp.workshop.policy.impl.DefaultPickingMoPolicy;
import com.mxpio.erp.workshop.policy.impl.ManufactureOrderSavePolicy;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "ManufactureOrderController", description = "生产订单接口")
@RestController
@RequestMapping("/erp/workshop/mo/")
public class ManufactureOrderController {

	@Autowired
	private ManufactureOrderService manufactureOrderService;
	
	@Autowired
	private ManufactureOrderItemService manufactureOrderItemService;
    @Autowired
    private ManufactureOrderRouteService manufactureOrderRouteService;
	
	@Autowired
	private OrderService bizOrderService;
	
	@Autowired
    private ManufactureOrderSavePolicy manufactureOrderSavePolicy;

    @Autowired
    private OrderLineService bizOrderLineService;
	@GetMapping("list")
    @Operation(summary = "生产订单列表", description = "获取生产订单列表（无分页）", method = "GET")
    public Result<List<ManufactureOrder>> list(@Parameter(description="查询参数") Criteria criteria) throws UnsupportedEncodingException {
        List<ManufactureOrder> manufactureOrders = manufactureOrderService.list(ManufactureOrder.class, criteria);
        return Result.OK(manufactureOrders);
    }

    @GetMapping("page")
    @Operation(summary = "生产订单列表", description = "获取生产订单列表（分页）", method = "GET")
    public Result<Page<ManufactureOrder>> page(@Parameter(description="查询参数") Criteria criteria, @Parameter(description="每页条数")Integer pageSize, @Parameter(description="页号")Integer pageNo) throws UnsupportedEncodingException {
        Pageable page = PageRequest.of(pageNo-1, pageSize);
        Page<ManufactureOrder> pageResult = manufactureOrderService.listPage(ManufactureOrder.class, page, criteria);
        //manufactureOrderService.handleManufactureOrderQuantity(pageResult.getContent(), OrderEnums.AccessType.IN.getCode());
        NoticeClassVo moInNoticeClazz = new NoticeClassVo(MoInNotice.class, MoInNoticeLine.class);//生产入库通知单
        NoticeClassVo moInQualityOrderClazz = new NoticeClassVo(MoInQualityOrder.class, MoInQualityOrderLine.class);//生产入库检验单
        List<NoticeClassVo> noticeClassVos = new ArrayList<>();
        noticeClassVos.add(moInNoticeClazz);
        noticeClassVos.add(moInQualityOrderClazz);
        bizOrderService.handleBizOrderQuantity(pageResult.getContent(),noticeClassVos,OrderEnums.AccessType.IN.getCode());
        return Result.OK(pageResult);
    }

    @GetMapping("list/{bizNo}")
    @Operation(summary = "根据bizNo获取生产订单", description = "根据bizNo获取生产订单", method = "GET")
    public Result<ManufactureOrder> getById(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
        ManufactureOrder manufactureOrder = manufactureOrderService.getById(ManufactureOrder.class, bizNo);
        return Result.OK(manufactureOrder);
    }

    @RequestMapping("save")
    @Operation(summary = "保存生产订单", description = "保存生产订单")
    public Result<ManufactureOrder> save(@RequestBody ManufactureOrder manufactureOrder) {
        String orderType = manufactureOrder.getOrderType();
        //返工订单保存不处理 订单工艺路线
        if (StringUtils.equals("03",orderType)){
            manufactureOrderService.save(manufactureOrder,new SmartCrudPolicyAdapter(){
                @Override
                public boolean beforeInsert(CrudContext context) {
                    Object o = context.getEntity();
                    if(o instanceof ManufactureOrderItem){
                        ManufactureOrder order = context.getParent();
                        ((ManufactureOrderItem) o).setBizNo(order.getBizNo());
                    }
                    return true;
                }
            });
            return Result.OK(manufactureOrder);
        }else{
            manufactureOrderService.save(manufactureOrder,manufactureOrderSavePolicy);
            Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, manufactureOrder.getBizNo());
            manufactureOrder.setManufactureOrderItems(manufactureOrderItemService.list(ManufactureOrderItem.class, c));
            manufactureOrder.setManufactureOrderRoutes(manufactureOrderRouteService.list(ManufactureOrderRoute.class, c));
            return Result.OK(manufactureOrder);
        }
    }
    
    @RequestMapping("excute/{bizNo}")
    @Operation(summary = "订单报完工", description = "订单报完工")
    public Result<Object> excute(@PathVariable(name = "bizNo", required = true) String bizNo, 
    		@RequestBody OrderExcuteVo orderExcuteVo) {
        if (orderExcuteVo==null||CollectionUtil.isEmpty(orderExcuteVo.getLines())){
            return Result.error("请求参数对象为空！");
        }
    	ManufactureOrder order = manufactureOrderService.getById(ManufactureOrder.class, bizNo);
        if (StringUtils.equals("03",order.getOrderType())){//如果是返工订单，入库必须走质检
            orderExcuteVo.getLines().forEach(m->{
                m.setInQualityControl("1");//指定需要生成检验单
            });
        }else{
            //普通和计划订单，成品完工入库根据物料组或物料设置的是否入库检来控制是否走验收单
            bizOrderService.handleInQualityControl(orderExcuteVo.getLines());
        }

        /*if (orderExcuteVo.getLines()!=null&&orderExcuteVo.getLines().size()>0){
            orderExcuteVo.getLines().forEach(m->{
                m.setInQualityControl("1");//指定需要生成检验单
            });
        }*/
    	OrderContext context = bizOrderService.execute(order, new DefaultExecuteMoPolicy(orderExcuteVo.getLines(),bizOrderService, bizOrderLineService));
    	if(CollectionUtils.isEmpty(context.getErrors())) {
    		return Result.OK();
    	}else {
    		return Result.error(context.getErrors().get(0));
    	}
    }
    
    @RequestMapping("excute/{type}/{bizNo}")
    @Operation(summary = "领/退/补料", description = "领/退/补料")
    public Result<Object> excute(@PathVariable(name = "bizNo", required = true) String bizNo, 
    		@PathVariable(name = "type", required = true) @Parameter(description = "-1:退料；2：补料；1：领料") String type,
    		@RequestBody OrderExcuteVo orderExcuteVo) {
    	ManufactureOrder order = manufactureOrderService.getById(ManufactureOrder.class, bizNo);
    	if (order.getCloseStatus().equals(OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())){
            return Result.error("关闭状态不能执行该操作");
        }
        if (order.getOrderStatus().equals(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())){
            return Result.error("已完成状态不能执行该操作");
        }
        if (order.getOrderStatus().equals(OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())){
            return Result.error("已结算状态不能执行该操作");
        }
    	OrderContext context = bizOrderService.execute(order, new DefaultPickingMoPolicy(orderExcuteVo.getLines(), type, bizOrderLineService));
    	if(CollectionUtils.isEmpty(context.getErrors())) {
    		return Result.OK();
    	}else {
    		return Result.error(context.getErrors().get(0));
    	}
    }

    @RequestMapping("excuteScrap/{bizNo}")
    @Operation(summary = "不良品退料", description = "不良品退料")
    public Result<Object> excuteScrap(@PathVariable(name = "bizNo", required = true) String bizNo,
                                 @RequestBody OrderExcuteVo orderExcuteVo) {
        ManufactureOrder order = manufactureOrderService.getById(ManufactureOrder.class, bizNo);
        if (order.getCloseStatus().equals(OrderStatusEnums.CloseStatus.CLOSED.getStatusCode())){
            return Result.error("关闭状态不能执行该操作");
        }
        if (order.getOrderStatus().equals(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode())){
            return Result.error("已完成状态不能执行该操作");
        }
        if (order.getOrderStatus().equals(OrderStatusEnums.OrderStatus.CLEARED.getStatusCode())){
            return Result.error("已结算状态不能执行该操作");
        }
        OrderContext context = bizOrderService.execute(order, new DefaultDefectivePolicy(orderExcuteVo.getLines(), bizOrderLineService));
        if(CollectionUtils.isEmpty(context.getErrors())) {
            return Result.OK();
        }else {
            return Result.error(context.getErrors().get(0));
        }
    }
    @DeleteMapping("remove/{bizNos}")
    @Operation(summary = "根据bizNo删除生产订单", description = "删除生产订单", method = "DELETE")
    @Transactional(readOnly = false)
    public Result<ManufactureOrder> remove(@Parameter(description="业务单号，多个单号用英文逗号分隔") @PathVariable(name = "bizNos", required = true) String bizNos) {
        String[] bizNo = bizNos.split(",");
        for(String key : bizNo){
        	Criteria c = Criteria.create().addCriterion("bizNo", Operator.EQ, key);
        	manufactureOrderItemService.removeBatch(ManufactureOrderItem.class, c);
            manufactureOrderService.delete(ManufactureOrder.class, key);
        }
        return Result.OK();
    }
    
    @PutMapping("submit/{bizNo}")
    @Operation(summary = "提交生产订单", description = "提交生产订单", method = "PUT")
    public Result<? extends Order> submit(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder so = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
    	if(so.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.CREATE.getStatusCode())){
    		return bizOrderService.updateBpmnStatus(so, OrderStatusEnums.BpmnStatus.AUDITING);
    	}else {
    		return Result.error("非开立状态不可提交");
		}
    }

    @PutMapping("audit/{bizNo}")
    @Operation(summary = "审核生产订单", description = "审核生产订单", method = "PUT")
    public Result<? extends Order> audit(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder so = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
    	if(so.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())){
    		return bizOrderService.updateBpmnStatus(so, OrderStatusEnums.BpmnStatus.AUDITED);
    	}else {
    		return Result.error("非审核中状态不可审核");
		}
    }

    @PutMapping("abandon/{bizNo}")
    @Operation(summary = "弃审生产订单", description = "弃审生产订单", method = "PUT")
    public Result<? extends Order> abandon(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder mo = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
    	if(mo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITING.getStatusCode())||mo.getBpmnStatus().equals(OrderStatusEnums.BpmnStatus.AUDITED.getStatusCode())){
    		return bizOrderService.updateBpmnStatus(mo, OrderStatusEnums.BpmnStatus.CREATE);
    	}else{
    		return Result.error("非审核中、已审核状态不可审核");
    	}
    }

    @PutMapping("export/{bizNos}")
    @Operation(summary = "导出生产订单", description = "导出生产订单", method = "PUT")
    public Result<ManufactureOrder> export(@Parameter(description="业务单号，多个单号用英文逗号分隔") @PathVariable(name = "bizNos", required = true) String bizNos) {
        //TODO:导出逻辑
        return Result.OK();
    }

    @PutMapping("open/{bizNo}")
    @Operation(summary = "打开生产订单", description = "打开生产订单", method = "PUT")
    public Result<? extends Order> open(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder mo = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
    	return bizOrderService.updateCloseStatus(mo, OrderStatusEnums.CloseStatus.OPEN);
    }

    @PutMapping("close/{bizNo}")
    @Operation(summary = "关闭生产订单", description = "关闭生产订单", method = "PUT")
    public Result<? extends Order> close(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder mo = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
    	return bizOrderService.updateCloseStatus(mo, OrderStatusEnums.CloseStatus.CLOSED);
    }
    
    @PutMapping("order/{bizNo}")
    @Operation(summary = "下达生产订单", description = "下达生产订单", method = "PUT")
    public Result<? extends Order> order(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder mo = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
        List<ManufactureOrderItem> itemList = manufactureOrderItemService.listByBizNo(bizNo);
        if (itemList==null|| itemList.size()==0){
            return Result.error("订单BOM为空，无法下达，请添加！");
        }
    	if(OrderStatusEnums.OrderStatus.PLAN.getStatusCode().equals(mo.getOrderStatus())){
    		return bizOrderService.updateOrderStatus(mo, OrderStatusEnums.OrderStatus.ORDERED);
    	}else{
    		return Result.error("非计划状态不可下达");
    	}
    }
    
    @PutMapping("clear/{bizNo}")
    @Operation(summary = "结算生产订单", description = "结算生产订单", method = "PUT")
    public Result<? extends Order> clear(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
        return manufactureOrderService.clearOrder(bizNo);
    }
    
    @PutMapping("finish/{bizNo}")
    @Operation(summary = "生产订单强制完工", description = "生产订单强制完工", method = "PUT")
    public Result<? extends Order> finish(@Parameter(description="业务单号") @PathVariable(name = "bizNo", required = true) String bizNo) {
    	ManufactureOrder mo = manufactureOrderService.getById(ManufactureOrder.class,bizNo);
        if(OrderStatusEnums.CloseStatus.CLOSED.getStatusCode().equals(mo.getCloseStatus())){
            return Result.error("已关闭状态不可报完工");
        }
        if(OrderStatusEnums.OrderStatus.CLEARED.getStatusCode().equals(mo.getOrderStatus())){
            return Result.error("已结清状态不可报完工");
        }
        if(OrderStatusEnums.OrderStatus.FINISHED.getStatusCode().equals(mo.getOrderStatus())){
            return Result.error("已完成状态不可重复报完工");
        }
        return bizOrderService.updateOrderStatus(mo, OrderStatusEnums.OrderStatus.FINISHED);
    	/*if(OrderStatusEnums.OrderStatus.PROCESSING.getStatusCode().equals(mo.getOrderStatus())){
    		return bizOrderService.updateOrderStatus(mo, OrderStatusEnums.OrderStatus.FINISHED);
    	}else{
    		return Result.error("非执行状态不可报完工");
    	}*/
    }

    @GetMapping("materialkitting")
    @Operation(summary = "重新 齐套分析（7、3、1对应的齐套率）", description = "重新 齐套分析（7、3、1对应的齐套率）", method = "GET")
    public Result<MaterialKittingAnalysisHistory> materialKittingAnalysis(){
        return manufactureOrderService.materialKittingAnalysis();
    }
    @GetMapping("shortageanalysis")
    @Operation(summary = "缺件分析", description = "缺件分析", method = "GET")
    public Result<List<MoStortageAnalysisVO>> shortageAnalysis(@Parameter(description="查询参数") Criteria criteria){
        return manufactureOrderService.shortageAnalysis(criteria);
    }


    @GetMapping("materialfeeding/{itemcode}")
    @Operation(summary = "物料供给明细", description = "物料供给明细", method = "GET")
    public Result<List<MaterialFeedingDetailVO>> materialFeedingAnalysis(@Parameter(description="物料编码") @PathVariable(name = "itemcode", required = true) String itemCode){
        return manufactureOrderService.materialFeedingAnalysis(itemCode);
    }

    @GetMapping("costaccounting/page")
    @Operation(summary = "成本核算(分页)", description = "成本核算(分页)，查询构造器中支持三个查询条件：beginDate(开始日期)、endDate(结束日期)、bizNo(生产订单号)", method = "GET")
    public Result<Page<MoCostAccountingVO>> costAccounting(@Parameter(description="查询参数") Criteria criteria, @Parameter(description="每页条数")Integer pageSize, @Parameter(description="页号")Integer pageNo) throws IllegalAccessException {
        return manufactureOrderService.costAccounting(criteria,pageSize,pageNo);
    }
}
